﻿using SUNRPA.CONTROLS.IMPL.domain;
using SUNRPA.CONTROLS.IMPL.domain.constant;
using SUNRPA.CONTROLS.IMPL.domain.flowItemParam;
using SUNRPA.CONTROLS.IMPL.domain.flowRunningVar;
using System.Collections.Concurrent;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;

/// <summary>
/// 扩展方法
/// </summary>
namespace SUNRPA.CONTROLS.IMPL.util {
    public static class ExtensionMethods {
        public static  Regex SUBFIELD_PATTERN = new Regex(@"\[[a-zA-Z0-9\+\-_\.\^\%~]+\]|\.[a-zA-Z0-9\+\-_\.\^\%~\(\)]+");

        public static void saveVar(this Object o, ConcurrentDictionary<string, ConcurrentDictionary<string, RPAVariableDefineWrapper>> golgbleData, 
            string paramName, RPAVariable paramValue, string paramType, [Optional]FlowItem item){
            if(golgbleData[paramType].ContainsKey(paramName)) { 
                golgbleData[paramType][paramName].Variable = paramValue;
            } else { 
                golgbleData[paramType].TryAdd(paramName, new RPAVariableDefineWrapper(paramValue, paramValue.GetType(), item));
            }
        }

        public static bool CheckVarExist(this System.Windows.Controls.Control con,ConcurrentDictionary<string, ConcurrentDictionary<string, RPAVariableDefineWrapper>> golgbleData, string paramName) {
            if(golgbleData[DefaultContents.GLOBLE_PARAM].ContainsKey(paramName) 
                || golgbleData[DefaultContents.RUNNING_PARAM].ContainsKey(paramName)) {
                return true;
            }
            return false;
        }
        
        private static object? GetVar(this Object? o, ConcurrentDictionary<string, ConcurrentDictionary<string, RPAVariableDefineWrapper>> golgbleData, string paramName) {
            string realName = paramName;
            int firstDot = paramName.IndexOf(".");
            int firstM = paramName.IndexOf("[");
            int subFieldStart;
            if(firstDot > 0 && firstM > 0) { 
                subFieldStart = Math.Min(firstDot, firstM);
            } else { 
                subFieldStart = Math.Max(firstDot, firstM);
            }
            if(subFieldStart > 0) { 
                realName = paramName.Substring(0, subFieldStart);
            }
            RPAVariableDefineWrapper param = null;
            try { 
                if(golgbleData[DefaultContents.RUNNING_PARAM].ContainsKey(realName)) { 
                    param = golgbleData[DefaultContents.RUNNING_PARAM][realName];
                }
                if(golgbleData[DefaultContents.GLOBLE_PARAM].ContainsKey(paramName)) { 
                    param = golgbleData[DefaultContents.GLOBLE_PARAM][realName];
                }
                if(param == null) { 
                    return null;
                }
                if(subFieldStart <= 0) {
                    if(param.Variable == null) {
                        throw new RpaRuntimeException($"获取参数变量{paramName}发生错误，参数可能不存在");
                    }
                    return param.Variable;
                } else { 
                    MatchCollection matches = SUBFIELD_PATTERN.Matches(paramName);
                    object tempVar = param.Variable;
                    foreach(Match subField in matches) { 
                        string field = subField.Value;
                        if(field.StartsWith(".")) {
                            if(field.Contains("(") && field.Contains(")")) {
                                //函数
                                tempVar = tempVar.ExecuteDynamicMethod(field.Substring(1, field.IndexOf("(") - 1));
                            } else { 
                                //属性
                                tempVar = tempVar.GetModelValueByFieldName(field.Substring(1));
                            }
                        } else { 
                            dynamic tempDyna = tempVar;
                            //数组或字典类型
                            field = field.Substring(1, field.Length - 2);
                            if(int.TryParse(field, out int index)) {
                                tempVar = tempDyna[index];
                            } else { 
                                tempVar = tempDyna[field];
                            }
                        }
                    }
                    if(tempVar == null) { 
                        throw new RpaRuntimeException($"获取参数变量{paramName}发生错误，参数可能不存在");
                    }
                    return tempVar;
                }
            }catch(Exception e){ 
                throw new RpaRuntimeException($"获取参数变量{paramName}发生错误，参数可能不存在");
            }
        }
        /// <summary>
        /// 变量分为字符串和对象类型，控件开发的时候可以明确知道该控件能用什么类型的变量所以取变量值得时候用相应的方法
        /// 而且所有的文本框都改为可以取变量的形式，然后对每个属性研究其变量类型
        /// 由于时间和历史原因暂时针对性的对每个控件调用变量取值，这次任务完成后变量框架大改直接改为取属性时直接取值并且开始规范变量类型
        /// 穷举所有的变量类型，为将来以后变量选取是展示什么样子的视图
        /// </summary>
        /// <param name="o"></param>
        /// <param name="originalStr"></param>
        /// <param name="globleData"></param>
        /// <returns></returns>
        public static List<string> GetStringVar(this Object? o, ref string originalStr, ConcurrentDictionary<string, ConcurrentDictionary<string, RPAVariableDefineWrapper>> globleData) {
            if(originalStr == null) {
                originalStr = "";
            }
            MatchCollection matches = DefaultContents.PARAM_PATTERN.Matches(originalStr);
            List<string> specialKey = new List<string>();
            foreach(Match m in matches) {
                string varialble = m.Groups[0].Value.Substring(1,m.Groups[0].Value.Length - 2);
                bool flag = DefaultContents.RESERVEVARS.ContainsKey(varialble);
                if(!flag) {
                    string varValue = GetVar(null, globleData, varialble).ToString();
                    if(varValue != null) { 
                        originalStr = originalStr.Replace(m.Value, varValue);
                    }
                } else { 
                    specialKey.Add(m.Value);
                    originalStr = originalStr.Replace(m.Value, "<|>");
                }
            }
            return specialKey;
        }

        public static T GetObjVar<T>(this Object? o, ref string originalStr, ConcurrentDictionary<string, ConcurrentDictionary<string, RPAVariableDefineWrapper>> globleData) { 
            MatchCollection matches = DefaultContents.PARAM_PATTERN.Matches(originalStr);
            if(matches.Count != 1 || !string.IsNullOrEmpty(DefaultContents.PARAM_PATTERN.Replace(originalStr, "").Trim())) { 
                throw new RpaRuntimeException("参数格式错误");
            }
            string varialble = originalStr.Substring(1, originalStr.Length - 2);
            bool flag = DefaultContents.RESERVEVARS.ContainsKey(varialble);
            if(!flag) {
                object target = GetVar(null, globleData, varialble);
                if(!target.GetType().Equals(typeof(T))) {
                     throw new RpaRuntimeException($"参数{originalStr}类型错误");
                }
                return (T)target;
            } else { 
                throw new RpaRuntimeException("参数类型错误");
            }
        }

        public static string GetLatestName(this BaseParam param, string defaultName, ConcurrentDictionary<string, ConcurrentDictionary<string, RPAVariableDefineWrapper>> globleData) { 
            int num = 1;
            string temp = defaultName;
            while(globleData[DefaultContents.RUNNING_PARAM].ContainsKey(defaultName)
                || globleData[DefaultContents.GLOBLE_PARAM].ContainsKey(defaultName)) {
                defaultName = temp + num;
                num++;
            }
            return defaultName;
        }

        public static UserInfo GetCurrentUser(this object obj) { 
            return FrontUiDelegateUtil.getUserInfoDel();
        }

        public static object GetGloBalVar(this object obj, string key) { 
            return FrontUiDelegateUtil.getGlobalVarDel(key);
        }

        public static void setGloBalVar(this object obj, string key, object value) { 
            FrontUiDelegateUtil.setGlobalVardel(key, value);
        }

        public static object GetModelValueByFieldName(this object obj, string fieldName) { 
            Type type = obj.GetType();
            FieldInfo fi = type.GetField(fieldName);
            if(fi == null) {
                PropertyInfo proi = type.GetProperty(fieldName);
                if(proi == null) {
                    return null;
                }
                return proi.GetValue(obj);
            }
            return fi.GetValue(obj);
        }

        public static object ExecuteDynamicMethod(this object obj, string methodName) { 
            Type type = obj.GetType();
            MethodInfo method = type.GetMethod(methodName);
            return method.Invoke(obj, null);
        }
    }
}
